package com.otomotion.research.ants.core;

import com.otomotion.research.ants.databank.UberRepository;
import com.otomotion.research.ants.entities.Ant;
import com.otomotion.research.ants.entities.Dirt;
import com.otomotion.research.ants.information.Coordinate;
import com.otomotion.research.ants.information.Information;
import com.otomotion.research.ants.request.DropRequest;
import com.otomotion.research.ants.request.MoveRequest;
import com.otomotion.research.ants.request.PickUpRequest;
import com.otomotion.research.ants.request.Request;
import com.otomotion.research.ants.util.LOGGER;
import java.util.Iterator;
import java.util.Vector;

/**
 * @author    joel
 */
public class Gaia
{

    UberRepository repository;

    Gaia(UberRepository repository)
    {
        this.repository = repository;
    }

    /* (non-Javadoc)
     * @see com.otomotion.research.ants.core.GaiaInterface#processAnt(com.otomotion.research.ants.entities.Ant)
     */
    public void processAnt(Ant ant)
    {
        Information info = this.getInformation(ant);
        Request request = ant.getNextRequest(info);
        if(this.validateRequest(ant, request))
        {
            this.perform(ant, request);
        }
    }

    private Information getInformation(Ant ant)
    {
        Coordinate c = repository.getLocationOf(ant);
        Vector coordinates = Coordinate.getTwentySevenAdjacentCoordinates(c);
        Information info = repository.getInformationForCoordinates(coordinates);
        return info;
    }

    private void perform(Ant ant, Request request)
    {
        Coordinate locationOfAnt = repository.getLocationOf(ant);
        
        if(request instanceof MoveRequest)
        {
            
            this.repository.moveAntTo(ant,locationOfAnt.add(((MoveRequest)request).getLocation()));
            LOGGER.log("      "+request.toString()+ " PERFORMED");
//            LOGGER.log("ant located at: "+ant.getLocation().toString());
        }
        else if(request instanceof PickUpRequest)
        {
            Coordinate target = locationOfAnt.add(((PickUpRequest)request).getLocation());
            this.repository.moveAntTo(ant,target);
            if (this.repository.hasDirt(target))
            {
                this.repository.clearDirt(target);
            }
            
            ant.setPayload(new Dirt());
            LOGGER.log("      "+request.toString()+ " PERFORMED");
//            LOGGER.log("ant located at: "+ant.getLocation().toString());
        }
        else if(request instanceof DropRequest)
        {
            if (ant.getPayload() instanceof Dirt)
            {
                ant.setPayload(null);
                this.repository.putDirt(locationOfAnt.add(((DropRequest)request).getLocation()));
            }
            
                
            LOGGER.log("      "+request.toString()+ " PERFORMED");
//            LOGGER.log("ant located at: "+ant.getLocation().toString());
        }



    }

    private boolean validateRequest(Ant ant, Request request)
    {
        LOGGER.logln("GAIA: ANT #"+ant.getId()+"["+ant.getLocation().toString()+"] Evaluating ");
        Coordinate locationOfAnt = repository.getLocationOf(ant);

        if(request instanceof MoveRequest)
        {
            LOGGER.logln(request.toString()+" ... ");
            Coordinate locationOfRequest = locationOfAnt.add(((MoveRequest) request).getLocation());
            if(repository.hasDirt(locationOfRequest) || repository.hasAnt(locationOfRequest))
            {
                LOGGER.log("DENIED [location not free]");
//                LOGGER.log("ant located at: "+ant.getLocation().toString());
                return false;
            }
            Vector coordinates = Coordinate.getSixAdjacentCoordinates(locationOfRequest);
            Iterator i = coordinates.iterator();
            while (i.hasNext())
            {
                if(repository.hasDirt((Coordinate) i.next()))
                {
                    LOGGER.log("GRANTED");
                    return true;
                }
            }
            LOGGER.log("DENIED [nothing to hold on to]");
//            LOGGER.log("ant located at: "+ant.getLocation().toString());
            return false;
        }
        else if(request instanceof PickUpRequest)
        {
            LOGGER.logln(request.toString()+" ... ");
            Coordinate locationOfRequest = locationOfAnt.add(((PickUpRequest) request).getLocation());
            if (ant.getPayload()!=null)
            {   
                LOGGER.log("DENIED [already carrying something]");
                return false;
            }
            if(repository.hasAnt(locationOfRequest)) //can't pickup other ants... for now
            {
                LOGGER.log("DENIED [can't pick up other ants... for now]");
//                LOGGER.log("ant located at: "+ant.getLocation().toString());
                return false;
            }
            if(!repository.isDirtMovable(locationOfRequest))
            {
                LOGGER.log("DENIED [unmovable dirt, probably map border]");
//              LOGGER.log("ant located at: "+ant.getLocation().toString());
              return false;
            }
            Vector coordinates = Coordinate.getSixAdjacentCoordinates(locationOfRequest);
            Iterator i = coordinates.iterator();
            while (i.hasNext())
            {
                if(repository.hasDirt((Coordinate) i.next()))
                {
                    LOGGER.log("GRANTED");
                    return true;
                }
            }
            LOGGER.log("DENIED [nothing to hold on to]");
//            LOGGER.log("ant located at: "+ant.getLocation().toString());
            return false;
        }
        else if(request instanceof DropRequest)
        {
            LOGGER.logln(request.toString()+" ... ");
            Coordinate locationOfRequest = locationOfAnt.add(((DropRequest) request).getLocation());
            
            if(repository.hasAnt(locationOfRequest)||repository.hasDirt(locationOfRequest))
            {
                LOGGER.log("DENIED [location not free]");
//                LOGGER.log("ant located at: "+ant.getLocation().toString());
                return false;
            }
            LOGGER.log("GRANTED");
            return true;
        }
        LOGGER.log("DENIED [unknown request]");
        return false;
    }

    /* (non-Javadoc)
     * @see com.otomotion.research.ants.core.GaiaInterface#processPhysics()
     */
    public void processPhysics()
    {
        // TODO Auto-generated method stub

    }

}
